#pragma once

using std::cout;
using std::endl;
using std::string;
using std::list;

struct ICmd
{
    virtual ~ICmd() { }

    virtual void Exec() = 0;
    virtual void Undo() = 0;
};

class CLampFlash    //  Receiver
{
public:
    CLampFlash() { }
    virtual ~CLampFlash() { }

public:
    void TurnOn()
    {
        cout << "Flash ON" << endl;
    }

    void TurnOff()
    {
        cout << "Flash OFF" << endl;
    }
};

class CLampFlashNoCmd : public ICmd     //  ConcreteCommand
{
public:
    CLampFlashNoCmd() { }
    virtual ~CLampFlashNoCmd() { }

public:
    virtual void Exec() { }
    virtual void Undo() { }
};

class CLampFlashOnCmd : public ICmd     //  ConcreteCommand
{
    CLampFlash* m_lpLampFlash;

    CLampFlashOnCmd() { }

public:
    CLampFlashOnCmd(CLampFlash* lpFlashLamp) : m_lpLampFlash(lpFlashLamp) { }
    virtual ~CLampFlashOnCmd() { }

public:
    virtual void Exec()
    {
        m_lpLampFlash->TurnOn();
    }

    virtual void Undo()
    {
        m_lpLampFlash->TurnOff();
    }
};

class CLampFlashOffCmd : public ICmd     //  ConcreteCommand
{
    CLampFlash* m_lpLampFlash;

    CLampFlashOffCmd() { }

public:
    CLampFlashOffCmd(CLampFlash* lpFlashLamp) : m_lpLampFlash(lpFlashLamp) { }
    virtual ~CLampFlashOffCmd() { }

public:
    virtual void Exec()
    {
        m_lpLampFlash->TurnOff();
    }

    virtual void Undo()
    {
        m_lpLampFlash->TurnOn();
    }
};

class CController   //  Invoker
{
    ICmd* m_lpCmd;
    ICmd* m_lpUndoCmd;

public:
    CController()
    {
        m_lpCmd = nullptr;
    }
    CController(ICmd* lpCmd) : m_lpCmd(lpCmd)
    {
    }
    virtual ~CController() { }

public:
    void SetCommand(ICmd* lpCmd)
    {
        m_lpCmd = lpCmd;
    }

    void Execute()
    {
        m_lpCmd->Exec();
    }

    void Undo()
    {
        m_lpCmd->Undo();
    }
};
